package tool.utils;


import com.alibaba.excel.util.DateUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author: chongyang
 * @Date: 2021/9/15
 */
public class DateUtil {
    public static final String PATTERN_DATETIME = "yyyy-MM-dd HH:mm:ss";
    public static final String PATTERN_DATE = "yyyy-MM-dd";
    public static final String PATTERN_TIME = "HH:mm:ss";
    /**
     * 老 date 格式化
     */
    public static final ConcurrentDateFormat DATETIME_FORMAT = ConcurrentDateFormat.of(PATTERN_DATETIME);
    public static final ConcurrentDateFormat DATE_FORMAT = ConcurrentDateFormat.of(PATTERN_DATE);
    public static final ConcurrentDateFormat TIME_FORMAT = ConcurrentDateFormat.of(PATTERN_TIME);
    /**
     * java 8 时间格式化
     */
    public static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern(PATTERN_DATETIME);
    public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(PATTERN_DATE);
    public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern(PATTERN_TIME);


    /*
    * 根据当前时间与type获取开始时间 如：获取本日的截止时间，返回当前时间所在的当日的开始时间
    * */
    public static Date changeDate(Integer dateType, Date date) {
        try {
            Date startDate = null;
            //切换日周
            if (dateType == 1) {
                startDate = cn.hutool.core.date.DateUtil.beginOfDay(date);
            } else {
                startDate = cn.hutool.core.date.DateUtil.beginOfWeek(date);
            }
            return startDate;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }


    /**
     * @param date1
     * @param date2
     * @return
     * @Author: minhua.yang
     * @Date: 2021/09/15
     * date2比date1多的天数
     */
    public static int differentDays(Date date1, Date date2) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        int day1 = cal1.get(Calendar.DAY_OF_YEAR);
        int day2 = cal2.get(Calendar.DAY_OF_YEAR);

        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);
        if (year1 != year2) //同一年
        {
            int timeDistance = 0;
            if (year1 <= year2) {
                for (int i = year1; i < year2; i++) {
                    if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) //闰年
                    {
                        timeDistance += 366;
                    } else //不是闰年
                    {
                        timeDistance += 365;
                    }
                }
            }
            if (year1 > year2) {
                for (int i = year2; i < year1; i++) {
                    if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) //闰年
                    {
                        timeDistance -= 366;
                    } else //不是闰年
                    {
                        timeDistance -= 365;
                    }
                }
            }

            return timeDistance + (day2 - day1);
        } else //不同年
        {
            return day2 - day1;
        }
    }

    /**
     * 将date转成ISODate 以便mongo识别
     *
     * @param dateStr
     * @return
     */
    public static Date dateToISODate(Date dateStr) {
        Date parse = null;
        try {
            // 解析字符串时间
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
            parse = format.parse(format.format(dateStr));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return parse;
    }

    /**
     * 字符串转时间，可识别常见类型
     *
     * @param dateStr 要转换的时间字符串
     * @return 转化后的时间
     * @throws Exception
     * @author minhua.yang
     * @date 2021-11-05 15:52:16
     */
    public static Date parseDate(String dateStr) throws Exception {
        dateStr = dateStr.trim();
        String pattern = "\\d{4}([^\\d]?)\\d{1,2}\\1\\d{1,2}( \\d{1,2}([^\\d])\\d{1,2})?";
        // 创建 Pattern 对象
        Pattern r = Pattern.compile(pattern);
        // 现在创建 matcher 对象
        Matcher m = r.matcher(dateStr);
        String dateSplit, timeSplit;
        if (m.find()) {
            dateSplit = m.group(1);
            timeSplit = m.group(3);
            String formatStr = String.format("yyyy%sMM%sdd", dateSplit, dateSplit);
            if (timeSplit != null) {
                String timeStr = dateStr.substring(dateStr.indexOf(" "));
                String[] split = timeStr.split(timeSplit);
                if (split.length == 2) {
                    formatStr += String.format(" HH%smm", timeSplit);
                }
                if (split.length > 2) {
                    formatStr += String.format(" HH%smm%sss", timeSplit, timeSplit);
                }
            }
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(formatStr);
            return simpleDateFormat.parse(dateStr);
        } else {
            throw new Exception("输入的时间格式不符");
        }
    }

    /**
     * 将秒数转化为时分秒格式
     *
     * @param time 秒数
     * @return java.lang.String
     * @author guodh
     * @date 2022/9/16
     */
    public static String timeFormat(long time) {
        int temp = (int) time;
        int hh = temp / 3600;
        int mm = (temp % 3600) / 60;
        int ss = (temp % 3600) % 60;
        return (hh < 10 ? ("0" + hh) : hh) + ":" +
                (mm < 10 ? ("0" + mm) : mm) + ":" +
                (ss < 10 ? ("0" + ss) : ss);
    }

    /**
     * 格式化日期：Mon Sep 05 00:00:00 CST 2022 转 yyyy-MM-dd
     * @param dateStr
     * @return
     */
    public static Date parse(String dateStr) {
        SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
        Date date = null;
        try{
            date = sdf.parse(dateStr);
        }catch (Exception e){
            e.printStackTrace();
        }
        return date;
    }

    /**
     * 拼接日期
     *
     * @param date  日期
     * @param joint 拼接时分秒
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static Date jointDate(Date date, String joint) {
        return DateUtil.parseDateTime(DateUtil.formatDate(date) + " " + joint);
    }

    public static Date parseDateTime(String dateStr) {
        ConcurrentDateFormat format = ConcurrentDateFormat.of(PATTERN_DATETIME);
        try {
            return format.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 日期格式化
     *
     * @param date 时间
     * @return 格式化后的时间
     */
    public static String formatDate(Date date) {
        if (Objects.nonNull(date)) {
            return DATE_FORMAT.format(date);
        }
        return null;
    }

    /**
     * 获取自然日期
     *
     * @param date 日期
     * @return {@link String}
     */
    public static String getNatureDate(Date date) {
        String format = DateUtils.format(date, "yyyy-MM-dd");
        String year = format.substring(0, 4);
        String month = format.substring(5,7);
        String day = format.substring(8, 10);
        return year+"年"+month+"月"+day+"日";
    }

    public static String getNextMonthOfDay(int day, int count) throws ParseException {
        if (day <= 0) {
            throw new IllegalArgumentException("day必须大于0");
        }
        Date currentDate = new Date();
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//        int month = org.assertj.core.util.DateUtil.monthOf(currentDate);
//        int year = org.assertj.core.util.DateUtil.yearOf(currentDate);
        calendar.setTime(currentDate);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.roll(Calendar.DAY_OF_MONTH, -1);
        int maxDate = calendar.get(Calendar.DATE);
//        String startDate = (day > maxDate) ? (year + "-" + month + "-" + maxDate) : (year + "-" + month + "-" + day);
//        calendar.setTime(sdf.parse(startDate));
        calendar.add(Calendar.MONTH, count);
        String newDate = sdf.format(calendar.getTime());
        calendar.setTime(sdf.parse(newDate));
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.roll(Calendar.DAY_OF_MONTH, -1);
        int nextMaxDate = calendar.get(Calendar.DATE);
        String[] split = newDate.split("-");
        int last = Integer.parseInt(split[2]);
        if (isDayValid(day, maxDate, nextMaxDate, last)) {
            return getResultDay(split, day, nextMaxDate);
        } else {
            throw new IllegalArgumentException("day不在有效范围内");
        }
    }

    private static boolean isDayValid(int day, int maxDate, int nextMaxDate, int last) {
        return (day >= maxDate && nextMaxDate >= day && day >= last) ||
                (day >= maxDate && day >= nextMaxDate && nextMaxDate >= last) ||
                (maxDate >= day && nextMaxDate >= day && day >= last) ||
                (maxDate >= day && day >= nextMaxDate);
    }

    private static String getResultDay(String[] split, int day, int nextMaxDate) {
        if (day >= nextMaxDate) {
            return split[0] + "-" + split[1] + "-" + nextMaxDate;
        } else {
            return split[0] + "-" + split[1] + "-" + day;
        }
    }

    /**
     * 时间加减处理
     *
     * @param date 当前时间
     * @param days 加减天数
     * @return
     */
    public static Date dateAdd(Date date, Integer days) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, days);
        date = calendar.getTime();
        return date;
    }

    /**
     * 比较2个 时间差
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return 时间间隔
     */
    public static Duration between(Date startDate, Date endDate) {
        return Duration.between(startDate.toInstant(), endDate.toInstant());
    }
}
